
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;

public class Main {
    public static void main(String[] args) {
        allocateThread();
    }
    public static String Path1 = "./algorithm/data/";//本机运行路径
    public static String Path2 = "../data/";//服务器运行路径
    public static String c = "" ;
    public static void allocateThread(){
        // 对每个文件启动一个线程进行处理
        String path = Path2;
        File file = new File(path);
        if (file.isDirectory()) {
            String[] names = file.list();
            for (int i = 0; i < names.length; i++) {
                new MyThread(names[i],names[i]).start();
            }
        }

    }
    public static class MyThread extends Thread {
        public MyThread(String name,String filename) {
            super(name);
            this.c = filename;
        }
        public String c ;
        @Override
        public void run()  {
            int fileId = Integer.parseInt(this.c);
            String path = Path2;
            File f1 = new File(Path2 + fileId + "/result.txt");
            if (!f1.exists()) {
                try {
                    f1.createNewFile();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
            BufferedWriter output = null;
            try {
                output = new BufferedWriter(new FileWriter(f1, true));
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            int timeIndex = 0;
            String portPath = Path2 +c+"/port.txt";
            String flowPath = Path2 +c+"/flow.txt";
            File f = new File(portPath);
            ArrayList<Port> portList = new ArrayList<>();//端口列表
            ArrayList<Point> pointList = new ArrayList<>();//数据流列表
            FileInputStream fin1 = null;
            FileInputStream fin2 = null;
            try {
                fin1 = new FileInputStream(portPath);
                fin2 = new FileInputStream(flowPath);
            } catch (FileNotFoundException e) {
                throw new RuntimeException(e);
            }
            InputStreamReader reader1 = new InputStreamReader(fin1);
            InputStreamReader reader2 = new InputStreamReader(fin2);
            BufferedReader buffReader1 = new BufferedReader(reader1);
            BufferedReader buffReader2 = new BufferedReader(reader2);
            String strTmp1 = null;
            try {
                strTmp1 = buffReader1.readLine();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            while(true){
                try {
                    if (!((strTmp1 = buffReader1.readLine())!=null)) break;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                String[] portResult = strTmp1.split(",");
                portList.add(new Port(Integer.parseInt(portResult[0]),Integer.parseInt(portResult[1])));
            }
            String strTmp2 = null;
            try {
                strTmp2 = buffReader2.readLine();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            while(true){
                try {
                    if (!((strTmp2 = buffReader2.readLine())!=null)) break;
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                String[] pointResult = strTmp2.split(",");
                pointList.add(new Point(Integer.parseInt(pointResult[0]),Integer.parseInt(pointResult[1]),Integer.parseInt(pointResult[2]),Integer.parseInt(pointResult[3])));
            }
            Collections.sort(portList);//端口按带宽大小逆序排序
            Collections.sort(pointList);//流数据按时间顺序排序
            ArrayList<Point> currentPointList = null;//当前时刻需处理的流列表
            while (!pointList.isEmpty()){
                //开始处理流数据，直到所有数据发送完成
                currentPointList = getProcessedData(pointList, timeIndex);
                try {
                    allocateData(portList, currentPointList, timeIndex,output);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
                timeIndex++;
            }
            try {
                output.flush();
                output.close();
                buffReader1.close();
                buffReader2.close();
                reader1.close();
                reader2.close();
                fin1.close();
                fin2.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
        public static void allocateData(ArrayList<Port> portList, ArrayList<Point> pointList, int timeIndex, BufferedWriter output) throws IOException {
            /**
             * @param pointList:当前需处理的数据流列表
             * @param timeIndex:时间戳
             * @param portList:端口列表
             * @return
             */
            /*
            遍历当前需处理的数据流列表pointList，对每个流选择可用带宽大于等于流占用带宽，
            并将流进入端口时间等相应信息写入result中，更新端口带宽信息。若没有满足条件的端口，则跳过该流。
             */
            Iterator<Port> iterator = portList.iterator();
            Port port = null;
            int count = 0;
            int index = 0 ;
            Point point = null;
            while (iterator.hasNext()){
                if(count == pointList.size()) break;
                port = iterator.next();
                index = 0 ;
                while (index < pointList.size()){
                    if(pointList.get(index).portId ==-1 && pointList.get(index).bandwidth <= port.availBandwidth){
                        pointList.get(index).portId = port.id;
                        pointList.get(index).endTime = timeIndex + pointList.get(index).spendTime;
                        pointList.get(index).port = port;
                        updatePort(pointList.get(index),1);
                        output.write(pointList.get(index).id + "," + pointList.get(index).portId + "," + timeIndex);
                        output.write("\r\n");//换行
                        count++;
                    }
                    index++;
                }
            }

        }

        public static ArrayList<Point> getProcessedData(ArrayList<Point> pointList, int timeIndex){
            /**
             * @param pointList:所有未处理数据流列表
             * @param timeIndex:时间戳
             * @return result:当前时刻需要处理的流列表
             */
            /*
            更新proceedPointList正在发送流的状态，当流发送结束时间满足当前时间，从相应端口中移除流并更新端口带宽情况。
            */
            Iterator<Point> iterator = pointList.iterator();
            ArrayList<Point> result = new ArrayList<>();
            Point next = null;
            while (iterator.hasNext()){
                next = iterator.next();
                if (next.endTime != -1 && timeIndex >= next.endTime) {
                    updatePort(next, 0);
                    iterator.remove();
                    continue;
                }
                if(next.startTime<=timeIndex&&next.portId == -1){
                    result.add(next);
                    continue;
                }
                if(next.startTime>timeIndex) break;
            }
            /*
            按照流价值逆序排列
            */
            Collections.sort(result, new Comparator<Point>() {
                @Override
                public int compare(Point point1, Point point2) {
                    if(point2.value - point1.value > 0 ) return -1;
                    else if (point2.value - point1.value == 0) return 0;
                    else return 1;
                }
            });
            return result;
        }
        public static void updatePort(Point point , int operateCode){
            //从portId端口中删除流，并更新port端口带宽信息
            if(operateCode == 0){
                point.port.availBandwidth += point.bandwidth;
                point.port.usedBandwidth -= point.bandwidth;
                return;
            }
            //从portId端口中添加流，并更新port端口带宽信息
            if (operateCode == 1){
                point.port.availBandwidth -= point.bandwidth;
                point.port.usedBandwidth += point.bandwidth;
                return;
            }
        }

        public static class Port implements Comparable<Port>{
            public int id;
            public int bandwidth;
            public int availBandwidth;
            public int usedBandwidth;
            public Port(int id, int bandwidth){
                this.id = id;
                this.bandwidth = bandwidth;
                this.availBandwidth = bandwidth;
            }

            @Override
            public String toString() {
                return "Port{" +
                        "id=" + id +
                        ", bandwidth=" + bandwidth +
                        ", availBandwidth=" + availBandwidth +
                        ", usedBandwidth=" + usedBandwidth +
                        '}';
            }

            @Override
            public int compareTo(Port port) {
                return port.availBandwidth - this.availBandwidth;
            }
        }
        public static class Point implements  Comparable<Point>{
            public int id;
            public int portId = -1;
            public int bandwidth;
            public int startTime;//流到达时间
            public int spendTime;//流占用时间
            public double value;//抽象流价值为bandwidth/spendTime比值
            public int endTime = -1;//流发送完成时间
            public Port port ;//流对应发送端口
            public Point(int id, int bandwidth, int startTime, int spendTime) {
                this.id = id;
                this.bandwidth = bandwidth;
                this.startTime = startTime;
                this.spendTime = spendTime;
                this.value = (double)bandwidth/(double)spendTime;
            }

            @Override
            public String toString() {
                return "Point{" +
                        "id=" + id +
                        ", portId=" + portId +
                        ", bandwidth=" + bandwidth +
                        ", startTime=" + startTime +
                        ", spendTime=" + spendTime +
                        ", value=" + value +
                        ", endTime=" + endTime +
                        '}';
            }

            @Override
            public int compareTo(Point point) {
                return this.startTime - point.startTime;
            }
        }
    }

}